﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace OverStore.Runtime.Storage
{
    /// <summary>
    /// Contains reference to <see cref="IDbCommand"/> instance and corresponding 
    /// objects like transaction and connection.
    /// </summary>
    public class DataCommandContainer : IDisposable
    {
        private readonly IDbCommand _Command;
        private readonly IDbConnection _Connection;
        private readonly IDbTransaction _Transaction;
        private readonly Func<DataCommandContainer, IDataReader> _CreateReaderFunc;
        private readonly object _OperationScope;
        private readonly bool _IsCommandReused;
        private IDataReader _Reader;

        /// <summary>
        /// Initializes a new instance of the <see cref="DataCommandContainer"/> class.
        /// </summary>
        /// <param name="command">The command.</param>
        /// <param name="operationScope">The operation scope.</param>
        /// <param name="createReader">The create reader.</param>
        /// <param name="isCommandReused">if set to <c>true</c> command was previously returned to caller.</param>
        public DataCommandContainer(IDbCommand command,
            object operationScope,
            Func<DataCommandContainer, IDataReader> createReader,
            bool isCommandReused)
        {
            if (Object.ReferenceEquals(command, null))
                throw new ArgumentNullException("command");
            if (Object.ReferenceEquals(operationScope, null))
                throw new ArgumentNullException("operationScope");
            if (Object.ReferenceEquals(createReader, null))
                throw new ArgumentNullException("createReader");
            _Command = command;
            _Connection = command.Connection;
            _Transaction = command.Transaction;
            _CreateReaderFunc = createReader;
            _OperationScope = operationScope;
            _IsCommandReused = isCommandReused;
        }

        /// <summary>
        /// Gets the command.
        /// </summary>
        /// <value>The command.</value>
        public IDbCommand Command { get { return _Command; } }

        /// <summary>
        /// Gets the connection.
        /// </summary>
        /// <value>The connection.</value>
        public IDbConnection Connection { get { return _Connection; } }

        /// <summary>
        /// Gets the transaction.
        /// </summary>
        /// <value>The transaction.</value>
        public IDbTransaction Transaction { get { return _Transaction; } }

        /// <summary>
        /// Gets the operation scope.
        /// </summary>
        public object OperationScope { get { return _OperationScope; } }

        /// <summary>
        /// Opens new <see cref="IDataReader"/> or returns existing one if reader was opened already.
        /// </summary>
        public IDataReader DataReader
        {
            get
            {
                if (_Reader == null)
                    _Reader = _CreateReaderFunc(this);
                return _Reader;
            }
        }

        /// <summary>
        /// Gets a value indicating whether is reader opened by the instance.
        /// </summary>
        public bool IsDataReaderOpened
        {
            get { return _Reader != null; }
        }

        /// <summary>
        /// Gets a value indicating whether Command property value is new command or instance was already used by the caller.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is command reused; otherwise, <c>false</c>.
        /// </value>
        public bool IsCommandReused { get { return _IsCommandReused; } }

            /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (Disposing != null)
                Disposing(this, EventArgs.Empty);
        }

        /// <summary>
        /// Occurs when Dispose method called.
        /// </summary>
        public event EventHandler Disposing;
    }
}
